﻿using System.IO;
using UnityEngine;
using YooAsset;

/// <summary>
/// 文件流加密方式
/// </summary>
public class SimpleFileStreamEncryption : IEncryptionServices
{
    public EncryptResult Encrypt(EncryptFileInfo fileInfo)
    {
        // 说明：对TestRes3资源目录进行加密
        if (fileInfo.BundleName.EndsWith(".bundle"))
        {
            var fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
            for (var i = 0; i < fileData.Length; i++)
            {
                fileData[i] ^= BundleStream.KEY;
            }

            var result = new EncryptResult
            {
                Encrypted = true,
                EncryptedData = fileData
            };
            return result;
        }
        else
        {
            var result = new EncryptResult
            {
                Encrypted = false
            };
            return result;
        }
    }
}

/// <summary>
/// 资源文件流解密类
/// </summary>
public class SimpleFileStreamDecryption : IDecryptionServices
{
    /// <summary>
    /// 同步方式获取解密的资源包对象
    /// </summary>
    public DecryptResult LoadAssetBundle(DecryptFileInfo fileInfo)
    {
        var bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
        var decryptResult = new DecryptResult
        {
            ManagedStream = bundleStream,
            Result = AssetBundle.LoadFromStream(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize())
        };
        return decryptResult;
    }

    /// <summary>
    /// 异步方式获取解密的资源包对象
    /// </summary>
    public DecryptResult LoadAssetBundleAsync(DecryptFileInfo fileInfo)
    {
        var bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
        var decryptResult = new DecryptResult
        {
            ManagedStream = bundleStream,
            CreateRequest =
                AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize())
        };
        return decryptResult;
    }

    /// <summary>
    /// 后备方式获取解密的资源包
    /// 注意：当正常解密方法失败后，会触发后备加载！
    /// 说明：建议通过LoadFromMemory()方法加载资源包作为保底机制。
    /// </summary>
    public DecryptResult LoadAssetBundleFallback(DecryptFileInfo fileInfo)
    {
        var fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
        var assetBundle = AssetBundle.LoadFromMemory(fileData);
        var decryptResult = new DecryptResult
        {
            Result = assetBundle
        };
        return decryptResult;
    }

    /// <summary>
    /// 获取解密的字节数据
    /// </summary>
    public byte[] ReadFileData(DecryptFileInfo fileInfo)
    {
        throw new System.NotImplementedException();
    }

    /// <summary>
    /// 获取解密的文本数据
    /// </summary>
    public string ReadFileText(DecryptFileInfo fileInfo)
    {
        throw new System.NotImplementedException();
    }

    private static uint GetManagedReadBufferSize()
    {
        return 1024;
    }
}

/// <summary>
/// 资源文件解密流
/// </summary>
public class BundleStream : FileStream
{
    public const byte KEY = 64;

    public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access,
        share)
    {
    }

    public BundleStream(string path, FileMode mode) : base(path, mode)
    {
    }

    public override int Read(byte[] array, int offset, int count)
    {
        var index = base.Read(array, offset, count);
        for (var i = 0; i < array.Length; i++)
        {
            array[i] ^= KEY;
        }

        return index;
    }
}